#include <AST/expr/function/PrototypeAST.hpp>
#include <global.hpp>

PrototypeAST::PrototypeAST(
    string funName,
    ParaTypeVector paraTypes,
    ParaNameVector paraNames,
    ParaIsRefVector paraIsRefs,
    Type *returnType)
    : funName(std::move(funName)),
      paraTypes(std::move(paraTypes)),
      paraNames(std::move(paraNames)),
      paraIsRefs(std::move(paraIsRefs)),
      returnType(returnType) {
    assert(this->paraTypes.size() == this->paraNames.size());
    assert(this->paraTypes.size() == this->paraIsRefs.size());
    std::cerr << "PrototypeAST::" << this->funName << "\n";
    for (auto &paraTy : this->paraTypes) { print_t(paraTy); }
    for (unsigned int i = 0; i < this->paraIsRefs.size(); ++i) {
        if (this->paraIsRefs[i]) {
            // 将引用切换为指针
            this->paraTypes[i] = this->paraTypes[i]->getPointerTo();
        } else {
            // 将原生数组标记为引用
            if (this->paraTypes[i]->isPointerTy()
                || this->paraTypes[i]->isArrayTy())
                this->paraIsRefs[i] = true;
        }
    }
    if (!theScope.insertProto(this->funName, this)) {
        logError("PrototypeAST::PrototypeAST: New prototype"
                 " is different from the older in "
                 + this->funName);
    }
    // TODO: 计算函数的返回值类型
}

llvm::FunctionType *PrototypeAST::getFunctionType() const {
    if (paraTypes.size() == 0) return FunctionType::get(returnType, false);
    return FunctionType::get(returnType, paraTypes, false);
}

llvm::Function *PrototypeAST::codegen() {
    // TODO
    // Make FunctionType
    FunctionType *funTy = getFunctionType();
    // 构造一个函数
    Function *fun =
        Function::Create(funTy, Function::ExternalLinkage, funName, theModule);
    // 给每个形参命名
    unsigned int i = 0;
    for (auto &arg : fun->args()) arg.setName(paraNames[i++]);

    return fun;
}

llvm::Type *PrototypeAST::getParaType(unsigned int i) const {
    return paraTypes[i];
}

bool PrototypeAST::getParaIsRef(unsigned int i) const {
    return paraIsRefs[i];
}
